home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / security / shadow-3.1.4 / smain.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-04-05  |  10.2 KB  |  475 lines

  1. /*
  2.  * Copyright 1989, 1990, 1991, John F. Haugh II
  3.  * All rights reserved.
  4.  *
  5.  * Permission is granted to copy and create derivative works for any
  6.  * non-commercial purpose, provided this copyright notice is preserved
  7.  * in all copies of source code, or included in human readable form
  8.  * and conspicuously displayed on all copies of object code or
  9.  * distribution media.
  10.  */
  11.  
  12. #include <sys/types.h>
  13. #include <stdio.h>
  14.  
  15. #ifndef    lint
  16. static    char    sccsid[] = "@(#)smain.c    3.11    21:21:19    3/7/92";
  17. #endif
  18.  
  19. /*
  20.  * Set up some BSD defines so that all the BSD ifdef's are
  21.  * kept right here 
  22.  */
  23.  
  24. #include "config.h"
  25. #if defined(USG) || defined(SUN4)
  26. #include <string.h>
  27. #include <memory.h>
  28. #define    bzero(a,n)    memset(a, 0, n)
  29. #include <termio.h>
  30. #else
  31. #include <strings.h>
  32. #include <sgtty.h>
  33. #define    strchr    index
  34. #define    strrchr    rindex
  35. #endif
  36.  
  37. #include <signal.h>
  38. #include "lastlog.h"
  39. #include "pwd.h"
  40. #include "shadow.h"
  41.  
  42. #ifdef    USE_SYSLOG
  43. #include <syslog.h>
  44.  
  45. /*VARARGS*/ int syslog();
  46.  
  47. #ifndef    LOG_WARN
  48. #define    LOG_WARN LOG_WARNING
  49. #endif    /* !LOG_WARN */
  50. #endif    /* USE_SYSLOG */
  51.  
  52. /*
  53.  * Password aging constants
  54.  *
  55.  *    DAY - seconds in a day
  56.  *    WEEK - seconds in a week
  57.  *    SCALE - convert from clock to aging units
  58.  */
  59.  
  60. #define    DAY    (24L*3600L)
  61. #define    WEEK    (7L*DAY)
  62.  
  63. #ifdef    ITI_AGING
  64. #define    SCALE    (1)
  65. #else
  66. #define    SCALE    DAY
  67. #endif
  68.  
  69. /*
  70.  * Assorted #defines to control su's behavior
  71.  */
  72.  
  73. #ifndef    MAXENV
  74. #define    MAXENV    128
  75. #endif
  76.  
  77. /*
  78.  * Global variables
  79.  */
  80.  
  81. char    hush[BUFSIZ];
  82. char    name[BUFSIZ];
  83. char    pass[BUFSIZ];
  84. char    home[BUFSIZ];
  85. char    prog[BUFSIZ];
  86. char    mail[BUFSIZ];
  87. char    oldname[BUFSIZ];
  88. char    *newenvp[MAXENV];
  89. char    *Prog;
  90. int    newenvc = 0;
  91. int    maxenv = MAXENV;
  92. struct    passwd    pwent;
  93.  
  94. /*
  95.  * External identifiers
  96.  */
  97.  
  98. extern    void    addenv ();
  99. extern    void    entry ();
  100. extern    void    sulog ();
  101. extern    void    subsystem ();
  102. extern    void    setup ();
  103. extern    void    motd ();
  104. extern    void    mailcheck ();
  105. extern    void    shell ();
  106. extern    char    *ttyname ();
  107. extern    char    *getenv ();
  108. extern    char    *getpass ();
  109. extern    char    *tz ();
  110. extern    char    *pw_encrypt();
  111. extern    struct    passwd    *getpwuid ();
  112. extern    struct    passwd    *getpwnam ();
  113. extern    struct    spwd    *getspnam ();
  114. extern    char    *getdef_str();
  115. extern    int    getdef_bool();
  116. extern    char    **environ;
  117.  
  118. /*
  119.  * die - set or reset termio modes.
  120.  *
  121.  *    die() is called before processing begins.  signal() is then
  122.  *    called with die() as the signal handler.  If signal later
  123.  *    calls die() with a signal number, the terminal modes are
  124.  *    then reset.
  125.  */
  126.  
  127. void    die (killed)
  128. int    killed;
  129. {
  130. #if defined(BSD) || defined(SUN)
  131.     static    struct    sgttyb    sgtty;
  132.  
  133.     if (killed)
  134.         stty (0, &sgtty);
  135.     else
  136.         gtty (0, &sgtty);
  137. #else
  138.     static    struct    termio    sgtty;
  139.  
  140.     if (killed)
  141.         ioctl (0, TCSETA, &sgtty);
  142.     else
  143.         ioctl (0, TCGETA, &sgtty);
  144. #endif
  145.     if (killed) {
  146. #ifdef    USE_SYSLOG
  147.         closelog ();
  148. #endif
  149.         exit (killed);
  150.     }
  151. }
  152.  
  153. /*
  154.  * su - switch user id
  155.  *
  156.  *    su changes the user's ids to the values for the specified user.
  157.  *    if no new user name is specified, "root" is used by default.
  158.  *
  159.  *    The only valid option is a "-" character, which is interpreted
  160.  *    as requiring a new login session to be simulated.
  161.  *
  162.  *    Any additional arguments are passed to the user's shell.  In
  163.  *    particular, the argument "-c" will cause the next argument to
  164.  *    be interpreted as a command by the common shell programs.
  165.  */
  166.  
  167. int    main (argc, argv, envp)
  168. int    argc;
  169. char    **argv;
  170. char    **envp;
  171. {
  172.     SIGTYPE    (*oldsig)();
  173.     char    *cp;
  174.     char    arg0[64];
  175.     char    *tty = 0;        /* Name of tty SU is run from        */
  176.     int    doshell = 0;
  177.     int    fakelogin = 0;
  178.     int    amroot = 0;
  179.     struct    passwd    *pw = 0;
  180.     struct    spwd    *spwd = 0;
  181.  
  182.     /*
  183.      * Get the program name.  The program name is used as a
  184.      * prefix to most error messages.  It is also used as input
  185.      * to the openlog() function for error logging.
  186.      */
  187.  
  188.     if (Prog = strrchr (argv[0], '/'))
  189.         Prog++;
  190.     else
  191.         Prog = argv[0];
  192.  
  193. #ifdef    USE_SYSLOG
  194.     openlog (Prog, LOG_PID|LOG_CONS|LOG_NOWAIT, LOG_AUTH);
  195. #endif
  196.  
  197.     /*
  198.      * Get the tty name.  Entries will be logged indicating that
  199.      * the user tried to change to the named new user from the
  200.      * current terminal.
  201.      */
  202.  
  203.     if (isatty (0) && (cp = ttyname (0))) {
  204.         if (strncmp (cp, "/dev/", 5) == 0)
  205.             tty = cp + 5;
  206.         else
  207.             tty = cp;
  208.     } else
  209.         tty = "???";
  210.  
  211.     /*
  212.      * Process the command line arguments. 
  213.      */
  214.  
  215.     argc--; argv++;            /* shift out command name */
  216.  
  217.     if (argc > 0 && argv[0][0] == '-' && argv[0][1] == '\0') {
  218.         fakelogin = 1;
  219.         argc--; argv++;        /* shift ... */
  220.     }
  221.  
  222.     /*
  223.      * If a new login is being set up, the old environment will
  224.      * be ignored and a new one created later on.
  225.      */
  226.  
  227.     if (! fakelogin)
  228.         while (*envp)
  229.             addenv (*envp++);
  230.  
  231.     if (fakelogin && (cp=getdef_str("ENV_TZ")))
  232.         addenv (*cp == '/' ? tz(cp) : cp);
  233.  
  234.     /*
  235.      * The clock frequency will be reset to the login value if required
  236.      */
  237.  
  238.     if (fakelogin && (cp=getdef_str("ENV_HZ")) )
  239.         addenv (cp);        /* set the default $HZ, if one */
  240.  
  241.     /*
  242.      * The terminal type will be left alone if it is present in the
  243.      * environment already.
  244.      */
  245.  
  246.     if (fakelogin && (cp = getenv ("TERM"))) {
  247.         char    term[BUFSIZ];
  248.  
  249.         sprintf (term, "TERM=%s", cp);
  250.         addenv (term);
  251.     }
  252.  
  253.     /*
  254.      * The next argument must be either a user ID, or some flag to
  255.      * a subshell.  Pretty sticky since you can't have an argument
  256.      * which doesn't start with a "-" unless you specify the new user
  257.      * name.  Any remaining arguments will be passed to the user's
  258.      * login shell.
  259.      */
  260.  
  261.     if (argc > 0 && argv[0][0] != '-') {
  262.         (void) strcpy (name, argv[0]);    /* use this login id */
  263.         argc--; argv++;        /* shift ... */
  264.     }
  265.     if (! name[0])             /* use default user ID */
  266.         (void) strcpy (name, "root");
  267.  
  268.     doshell = argc == 0;        /* any arguments remaining? */
  269.  
  270.     /*
  271.      * Get the user's real name.  The current UID is used to determine
  272.      * who has executed su.  That user ID must exist.
  273.      */
  274.  
  275.     if (pw = getpwuid (getuid ()))    /* need old user name */
  276.         (void) strcpy (oldname, pw->pw_name);
  277.     else {                /* user ID MUST exist */ 
  278. #ifdef    USE_SYSLOG
  279.         syslog (LOG_CRIT, "Unknown UID: %d\n", getuid ());
  280. #endif
  281.         goto failure;
  282.     }
  283.     amroot = getuid () == 0;    /* currently am super user */
  284.  
  285. top:
  286.     /*
  287.      * This is the common point for validating a user whose name
  288.      * is known.  It will be reached either by normal processing,
  289.      * or if the user is to be logged into a subsystem root.
  290.      *
  291.      * The password file entries for the user is gotten and the
  292.      * accont validated.
  293.      */
  294.  
  295.     if (pw = getpwnam (name)) {
  296.         if (spwd = getspnam (name))
  297.             pw->pw_passwd = spwd->sp_pwdp;
  298.     } else {
  299.         (void) fprintf (stderr, "Unknown id: %s\n", name);
  300. #ifdef    USE_SYSLOG
  301.         closelog ();
  302. #endif
  303.         exit (1);
  304.     }
  305.     pwent = *pw;
  306.  
  307.     /*
  308.      * See if the account is usable for anything but login.
  309.      */
  310.  
  311.     cp = getdef_str("NOLOGIN_STR");
  312.     if (cp != NULL && strcmp (pwent.pw_shell, cp) == 0)
  313.         pwent.pw_shell = getenv ("SHELL");
  314.  
  315.     /*
  316.      * Set the default shell.
  317.      */
  318.  
  319.     if (pwent.pw_shell == 0 || pwent.pw_shell[0] == '\0')
  320.         pwent.pw_shell = "/bin/sh";
  321.  
  322.     /*
  323.      * Set up a signal handler in case the user types QUIT.
  324.      */
  325.  
  326.     die (0);
  327.     oldsig = signal (SIGQUIT, die);
  328.  
  329.     /*
  330.      * Get the password from the invoker
  331.      */
  332.  
  333.     if (! amroot && pwent.pw_passwd[0]) {
  334.         if (! (cp = getpass ("Password:"))) {
  335. #ifdef    USE_SYSLOG
  336.             syslog (pwent.pw_uid ? LOG_WARN:LOG_CRIT,
  337.                 "Unable to get password for %s\n", name);
  338. #endif
  339.             goto failure;
  340.         } else
  341.             (void) strncpy (pass, cp, sizeof pass);
  342.     } else
  343.         bzero (pass, sizeof pass);
  344.  
  345.     /*
  346.      * check encrypted passwords ...
  347.      */
  348.  
  349.     if (! amroot && ((pass[0] != '\0' || pwent.pw_passwd[0] != '\0') &&
  350.             strcmp (pwent.pw_passwd,
  351.                 pw_encrypt (pass, pwent.pw_passwd)) != 0)) {
  352. #ifdef    USE_SYSLOG
  353.         syslog (pwent.pw_uid ? LOG_WARN:LOG_CRIT,
  354.             "Invalid password for %s\n", name);
  355. #endif
  356. failure:    sulog (0);        /* log failed attempt */
  357.         puts ("Sorry.");
  358. #ifdef    USE_SYSLOG
  359.         if ( getdef_bool("SYSLOG_SU_ENAB") )
  360.             syslog (pwent.pw_uid ? LOG_INFO:LOG_CRIT,
  361.                 "- %s %s-%s\n", tty ? tty:"???",
  362.                 oldname[0] ? oldname:"???",
  363.                 name[0] ? name:"???");
  364.         closelog ();
  365. #endif
  366.         exit (1);
  367.     }
  368.     (void) signal (SIGQUIT, oldsig);
  369.  
  370.     /*
  371.      * Check to see if the account is expired.  root gets to
  372.      * ignore any expired accounts, but normal users can't become
  373.      * a user with an expired password.
  374.      */
  375.  
  376.     if (! amroot) {
  377.         if (spwd) {
  378.             if (isexpired (&pwent, spwd)) {
  379. #ifdef    USE_SYSLOG
  380.                 syslog (pwent.pw_uid ? LOG_WARN:LOG_CRIT,
  381.                     "Expired account %s\n", name);
  382. #endif
  383.                 goto failure;
  384.             }
  385.         }
  386. #ifdef    ATT_AGE
  387.         else if (pwent.pw_age[0] &&
  388.                 isexpired (&pwent, (struct spwd *) 0)) {
  389. #ifdef    USE_SYSLOG
  390.             syslog (pwent.pw_uid ? LOG_WARN:LOG_CRIT,
  391.                 "Expired account %s\n", name);
  392. #endif
  393.             goto failure;
  394.         }
  395. #endif    /* ATT_AGE */
  396.     }
  397.  
  398.     cp = getdef_str( pwent.pw_uid == 0 ? "ENV_SUPATH" : "ENV_PATH" );
  399.     addenv( cp != NULL ? cp : "PATH=/bin:/usr/bin" );
  400.  
  401.     environ = newenvp;        /* make new environment active */
  402.  
  403.     if (getenv ("IFS"))        /* don't export user IFS ... */
  404.         addenv ("IFS= \t\n");    /* ... instead, set a safe IFS */
  405.  
  406.     if (doshell && pwent.pw_shell[0] == '*') { /* subsystem root required */
  407.         subsystem (&pwent);    /* figure out what to execute */
  408.         endpwent ();
  409.         endspent ();
  410.         goto top;
  411.     }
  412.  
  413.     sulog (1);            /* save SU information */
  414. #ifdef    USE_SYSLOG
  415.     if ( getdef_bool("SYSLOG_SU_ENAB") )
  416.         syslog (LOG_INFO, "+ %s %s-%s\n", tty ? tty:"???",
  417.             oldname[0] ? oldname:"???", name[0] ? name:"???");
  418. #endif
  419.     if (fakelogin)
  420.         setup (&pwent);        /* set UID, GID, HOME, etc ... */
  421.     else {
  422.         if (setgid (pwent.pw_gid) || setuid (pwent.pw_uid))  {
  423.             perror ("Can't set ID");
  424. #ifdef    USE_SYSLOG
  425.             syslog (LOG_CRIT, "Unable to set uid = %d, gid = %d\n",
  426.                 pwent.pw_uid, pwent.pw_gid);
  427.             closelog ();
  428. #endif
  429.             exit (1);
  430.         }
  431.     }
  432.     if (! doshell) {        /* execute arguments as command */
  433.         if (cp = getenv ("SHELL"))
  434.             pwent.pw_shell = cp;
  435.         argv[-1] = pwent.pw_shell;
  436.         (void) execv (pwent.pw_shell, &argv[-1]);
  437.         (void) fprintf (stderr, "No shell\n");
  438. #ifdef    USE_SYSLOG
  439.         syslog (LOG_WARN, "Cannot execute %s\n", pwent.pw_shell);
  440.         closelog ();
  441. #endif
  442.         exit (1);
  443.     }
  444.     if (fakelogin) {
  445.         if (! hushed (&pwent)) {
  446.             motd ();
  447.             mailcheck ();
  448.         }
  449.         if ((cp = getdef_str("SU_NAME")) == NULL) {
  450.             if (cp = strrchr (pwent.pw_shell, '/'))
  451.                 cp++;
  452.             else
  453.                     cp = pwent.pw_shell;
  454.         }
  455.         arg0[0] = '-';
  456.         strncpy(arg0+1, cp, sizeof(arg0)-1);
  457.         arg0[sizeof(arg0)-1] = '\0';
  458.         cp = arg0;
  459.     } else {
  460.         if (cp = strrchr (pwent.pw_shell, '/'))
  461.             cp++;
  462.         else
  463.                 cp = pwent.pw_shell;
  464.     }
  465.  
  466.     shell (pwent.pw_shell, cp);
  467. #ifdef    USE_SYSLOG
  468.     syslog (LOG_WARN, "Cannot execute %s\n", pwent.pw_shell);
  469.     closelog ();
  470. #endif
  471.     exit (1);
  472.  
  473.     /*NOTREACHED*/
  474. }
  475.